---
title: Custom Variants
description: Learn how to create new variants for the HeroUI components.
---

# Custom Variants

HeroUI allows you to create new variants for components by extending and customizing their styles. You can override the component's `variants`, `defaultVariants` and `compoundVariants`.

<CarbonAd/>

> **Note**: For one-off customizations, refer to the [Override Styles](/docs/customization/override-styles) documentation.

## Creating new variants for non-slots components

Let's use the [Button](/docs/components/button) component as an example. It's a non-slots component, and you can view its source styles [here](https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/button.ts).

> **Note**: If you are not familiar with the variants concept, please refer to the [Tailwind Variants](https://www.tailwind-variants.org/docs/variants) documentation.

<Steps>

### Extend the original component variants

Use the `extendVariants` function to create a new component with customized variants based on an existing component.

```tsx
// MyButton.tsx
import {extendVariants, Button} from "@heroui/react";

export const MyButton = extendVariants(Button, {
  variants: {
    // <- modify/add variants
    color: {
      olive: "text-[#000] bg-[#84cc16]",
      orange: "bg-[#ff8c00] text-[#fff]",
      violet: "bg-[#8b5cf6] text-[#fff]",
    },
    isDisabled: {
      true: "bg-[#eaeaea] text-[#000] opacity-50 cursor-not-allowed",
    },
    size: {
      xs: "px-2 min-w-12 h-6 text-tiny gap-1 rounded-small",
      md: "px-4 min-w-20 h-10 text-small gap-2 rounded-small",
      xl: "px-8 min-w-28 h-14 text-large gap-4 rounded-medium",
    },
  },
  defaultVariants: { // <- modify/add default variants
    color: "olive",
    size: "xl",
  },
  compoundVariants: [ // <- modify/add compound variants
    {
      isDisabled: true,
      color: "olive",
      class: "bg-[#84cc16]/80 opacity-100",
    },
  ],
});
```

### Use your custom component in your application

Then, you can now use your custom component in your application. Here, `MyButton` is
used with the color set to `olive` and the size set to `xl`.

```tsx
// App.tsx
import {MyButton} from "./MyButton";

const MyApp = () => {
  return (
    <MyButton color="olive" size="md">
      Press Me
    </MyButton>
  );
};
```

The new component will include the original props of the `Button` component, plus the new
variants that you have created.

import customVariantsNoSlots from "@/content/customization/custom-variants/no-slots-component";

<CodeDemo
  title="Custom Variants for non-slots components"
  showEditor={false}
  files={customVariantsNoSlots}
/>

</Steps>

## Creating new variants for slots components

The `extendVariants` function can also be used with slot-based components like [Input](/docs/components/input) to add or override variants. You can view the Input component's source styles [here](https://github.com/heroui-inc/heroui/blob/main/packages/core/theme/src/components/input.ts).

> **Note**: If you are not familiar with the variants/slots concept, please refer to the [Tailwind Variants](https://www.tailwind-variants.org/docs/slots#slots-with-variants) documentation.

<Steps>

### Extend the original component variants

Use the `extendVariants` function to create a new component with custom variants based on the original component.

```tsx
// MyInput.tsx
import {extendVariants, Input} from "@heroui/react";

const MyInput = extendVariants(Input, {
  variants: { // <- modify/add variants
    color: {
      stone: { // <- add a new color variant
        inputWrapper: [ // <- Input wrapper slot
          "bg-zinc-100",
          "border",
          "shadow-sm",
          "transition-colors",
          "focus-within:bg-zinc-100",
          "data-[hover=true]:border-zinc-600",
          "data-[hover=true]:bg-zinc-100",
          "group-data-[focus=true]:border-zinc-600",
          // dark theme
          "dark:bg-zinc-900",
          "dark:border-zinc-800",
          "dark:data-[hover=true]:bg-zinc-900",
          "dark:focus-within:bg-zinc-900",
        ],
        input: [  // <- Input element slot
          "text-zinc-800",
          "placeholder:text-zinc-600",
          // dark theme
          "dark:text-zinc-400",
          "dark:placeholder:text-zinc-600",
        ],
      },
    },
    size: {
      xs: {
        inputWrapper: "h-6 min-h-6 px-1",
        input: "text-tiny",
      },
      md: {
        inputWrapper: "h-10 min-h-10",
        input: "text-small",
      },
      xl: {
        inputWrapper: "h-14 min-h-14",
        input: "text-medium",
      },
    },
    radius: {
      xs: {
        inputWrapper: "rounded-sm",
      },
      sm: {
        inputWrapper: "rounded-[4px]",
      },
    },
    textSize: {
      base: {
        input: "text-base",
      },
    },
    removeLabel: {
      true: {
        label: "hidden",
      },
      false: {},
    },
  },
  defaultVariants: {
    color: "stone",
    textSize: "base",
    removeLabel: true,
  },
});
```

### Use your custom component in your application

Then, you can now use your custom component in your application. Here, `MyInput` is
used with the color set to `slate` and the size set to `xl`.

```tsx
// App.tsx
import {MyInput} from "./MyInput";
import {SearchIcon} from "your-icons-library";

const MyApp = () => {
  return (
    <MyInput
      isClearable
      placeholder="Search..."
      radius="md"
      size="md"
      startContent={<SearchIcon className="text-zinc-500" size={16} />}
    />
  );
};
```

The new component will include the original props of the [Input](/docs/components/input) component, plus the new
variants that you have created.

import customVariantsSlots from "@/content/customization/custom-variants/slots-component";

<CodeDemo
  title="Custom Variants for slots components"
  showEditor={false}
  files={customVariantsSlots}
/>

</Steps>

<Blockquote>
  Use the `Styles source` link at the top of each component page to view its source code as a reference for customization.
</Blockquote>

### Types

### Main Function

```jsx
const Component = extendVariants(BaseComponent, options, config);

/**
 * BaseComponent -> HeroUI component to extend
 * options -> the variants to add/modify
 * config -> config to extend the component
 */
```

### Options

```ts
type ExtendVariantsOptions = {
  variants?: Record<string, Record<string, ClassValue>>;
  defaultVariants?: Record<string, ClassValue>;
  compoundVariants?: Array<Record<string, string> & ClassProp>;
};
```

### Config

```ts
  /**
   * Whether to merge the class names with `tailwind-merge` library.
   * It's avoid to have duplicate tailwind classes. (Recommended)
   * @see https://github.com/dcastil/tailwind-merge/blob/v1.8.1/README.md
   * @default true
   */
  twMerge?: boolean;
  /**
   * The config object for `tailwind-merge` library.
   * @see https://github.com/dcastil/tailwind-merge/blob/v1.8.1/docs/configuration.md
   */
  twMergeConfig?: TWMergeConfig;
```

> **Note**: See the [Tailwind Merge Config](https://github.com/dcastil/tailwind-merge/blob/v1.8.1/docs/configuration.md) to learn more about it.
